package cn.chiship.sdk.core.util.http;

import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.base.constants.BaseConstants;
import cn.chiship.sdk.core.enums.StatusEnum;
import cn.chiship.sdk.core.exception.custom.BusinessException;
import cn.chiship.sdk.core.util.ObjectUtil;
import cn.chiship.sdk.core.util.StringUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 李剑 AliYun网络请求工具
 */
public class HttpUtils {

	private static final String NO_Q = "无效的请求!";

	private static final String A = "https://";

	private HttpUtils() {

	}

	public static BaseResult doGet(String host, String path) {
		return doGet(host, path, null, null);
	}

	public static BaseResult doGet(String host, String path, Map<String, String> queries) {
		return doGet(host, path, null, queries);
	}

	/**
	 * get
	 */
	public static BaseResult doGet(String host, String path, Map<String, String> headers, Map<String, String> queries) {
		try {
			HttpClient httpClient = wrapClient(host);
			HttpGet request = new HttpGet(buildUrl(host, path, queries));
			if (!StringUtil.isNull(headers)) {
				for (Map.Entry<String, String> e : headers.entrySet()) {
					request.addHeader(e.getKey(), e.getValue());
				}
			}
			return analysisHttpResponse(httpClient.execute(request));
		}
		catch (IOException e) {
			throw new BusinessException(NO_Q);
		}

	}

	/**
	 * post form application/x-www-form-urlencoded; charset=UTF-8
	 */
	public static BaseResult doPost(String host, String path, Map<String, String> bodies) {
		return doPost(host, path, null, null, bodies);
	}

	public static BaseResult doPost(String host, String path, Map<String, String> headers, Map<String, String> bodies) {
		return doPost(host, path, headers, null, bodies);
	}

	public static BaseResult doPost(String host, String path, Map<String, String> headers, Map<String, String> queries,
			Map<String, String> bodies) {
		try {
			HttpClient httpClient = wrapClient(host);
			HttpPost request = new HttpPost(buildUrl(host, path, queries));
			if (!StringUtil.isNull(headers)) {
				for (Map.Entry<String, String> e : headers.entrySet()) {
					request.addHeader(e.getKey(), e.getValue());
				}
			}

			if (!StringUtil.isNull(bodies)) {
				List<NameValuePair> nameValuePairList = new ArrayList<>();
				for (Map.Entry<String, String> entry : bodies.entrySet()) {
					nameValuePairList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
				}
				UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, StandardCharsets.UTF_8);
				formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
				request.setEntity(formEntity);
			}
			return analysisHttpResponse(httpClient.execute(request));
		}
		catch (IOException e) {
			throw new BusinessException(NO_Q);
		}
	}

	/**
	 * post body application/json
	 */
	public static BaseResult doPost(String host, String path, Map<String, String> headers, Map<String, String> queries,
			JSONObject json) {
		try {
			HttpClient httpClient = wrapClient(host);
			HttpPost request = new HttpPost(buildUrl(host, path, queries));
			if (!StringUtil.isNull(headers)) {
				for (Map.Entry<String, String> e : headers.entrySet()) {
					request.addHeader(e.getKey(), e.getValue());
				}
			}

			if (!StringUtil.isNull(json)) {
				StringEntity s = new StringEntity(json.toString());
				s.setContentEncoding(BaseConstants.UTF8);
				s.setContentType("application/json");
				request.setEntity(s);
			}

			return analysisHttpResponse(httpClient.execute(request));
		}
		catch (IOException e) {
			throw new BusinessException(NO_Q);
		}
	}

	/**
	 * post body application/json
	 */
	public static BaseResult doPost(String host, String path, Map<String, String> headers, Map<String, String> queries,
			JSONArray jsons) {
		try {
			HttpClient httpClient = wrapClient(host);

			HttpPost request = new HttpPost(buildUrl(host, path, queries));
			if (!StringUtil.isNull(headers)) {
				for (Map.Entry<String, String> e : headers.entrySet()) {
					request.addHeader(e.getKey(), e.getValue());
				}
			}

			if (!StringUtil.isNull(jsons)) {
				StringEntity s = new StringEntity(jsons.toString(), StandardCharsets.UTF_8);
				s.setContentEncoding("UTF-8");
				s.setContentType("application/json");
				request.setEntity(s);
			}

			return analysisHttpResponse(httpClient.execute(request));
		}
		catch (IOException e) {
			throw new BusinessException(NO_Q);
		}
	}

	/**
	 * Post String
	 */
	public static BaseResult doPost(String host, String path, Map<String, String> headers, Map<String, String> queries,
			String body) {
		try {
			HttpClient httpClient = wrapClient(host);
			HttpPost request = new HttpPost(buildUrl(host, path, queries));
			if (!StringUtil.isNull(headers)) {
				for (Map.Entry<String, String> e : headers.entrySet()) {
					request.addHeader(e.getKey(), e.getValue());
				}
			}

			if (StringUtil.isNotBlank(body)) {
				request.setEntity(new StringEntity(body, "utf-8"));
			}
			return analysisHttpResponse(httpClient.execute(request));
		}
		catch (IOException e) {
			throw new BusinessException(NO_Q);
		}
	}

	/**
	 * Post stream
	 */
	public static BaseResult doPost(String host, String path, Map<String, String> headers, Map<String, String> queries,
			byte[] body) {

		try {
			HttpClient httpClient = wrapClient(host);
			HttpPost request = new HttpPost(buildUrl(host, path, queries));
			if (!StringUtil.isNull(headers)) {
				for (Map.Entry<String, String> e : headers.entrySet()) {
					request.addHeader(e.getKey(), e.getValue());
				}
			}
			if (!StringUtil.isNull(body)) {
				request.setEntity(new ByteArrayEntity(body));
			}

			return analysisHttpResponse(httpClient.execute(request));
		}
		catch (IOException e) {
			throw new BusinessException(NO_Q);
		}
	}

	/**
	 * POST请求
	 * @param host 主机
	 * @param path 地址
	 * @param queries 条件
	 * @param fileMap 文件集合
	 * @return 结果
	 */
	public static BaseResult doFilePost(String host, String path, Map<String, String> queries,
			Map<String, File> fileMap) {
		return doFilePost(host, path, queries, null, fileMap);
	}

	/**
	 * POST请求
	 * @param host 主机
	 * @param path 地址
	 * @param queries 条件
	 * @param bodies Body
	 * @param fileMap 文件集合
	 * @return 结果
	 */
	public static BaseResult doFilePost(String host, String path, Map<String, String> queries,
			Map<String, String> bodies, Map<String, File> fileMap) {

		try {
			HttpPost httpPost = new HttpPost(buildUrl(host, path, queries));

			MultipartEntityBuilder meBuilder = MultipartEntityBuilder.create();

			if (null != bodies) {
				for (Map.Entry<String, String> m : bodies.entrySet()) {
					meBuilder.addPart(m.getKey(), new StringBody(m.getValue(), ContentType.TEXT_PLAIN));
				}
			}
			if (null != fileMap) {
				for (Map.Entry<String, File> m : fileMap.entrySet()) {
					FileBody fileBody = new FileBody(m.getValue());
					meBuilder.addPart(m.getKey(), fileBody);
				}
			}

			HttpEntity reqEntity = meBuilder.build();
			httpPost.setEntity(reqEntity);
			CloseableHttpClient httpClient = wrapClient(host);
			return analysisHttpResponse(httpClient.execute(httpPost));
		}
		catch (IOException e) {
			throw new BusinessException(NO_Q);
		}
	}

	private static String buildUrl(String host, String path, Map<String, String> queries)
			throws UnsupportedEncodingException {
		StringBuilder sbUrl = new StringBuilder();
		sbUrl.append(host);
		if (!StringUtil.isNullOrEmpty(path)) {
			sbUrl.append(path);
		}
		if (!StringUtil.isNull(queries)) {
			StringBuilder sbQuery = new StringBuilder();
			for (Map.Entry<String, String> query : queries.entrySet()) {
				if (0 < sbQuery.length()) {
					sbQuery.append("&");
				}
				if (StringUtil.isBlank(query.getKey()) && !StringUtil.isBlank(query.getValue())) {
					sbQuery.append(query.getValue());
				}
				if (!StringUtil.isBlank(query.getKey())) {
					sbQuery.append(query.getKey());
					if (!StringUtil.isBlank(query.getValue())) {
						sbQuery.append("=");
						sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
					}
				}
			}
			if (0 < sbQuery.length()) {
				sbUrl.append("?").append(sbQuery);
			}
		}

		return sbUrl.toString();
	}

	private static CloseableHttpClient wrapClient(String host) {
		CloseableHttpClient httpClient = HttpClients.createDefault();
		if (host.startsWith(A)) {
		}

		return httpClient;
	}

	public static BaseResult analysisHttpResponse(HttpResponse response) throws IOException {
		return analysisHttpResponse(response, BaseConstants.UTF8);
	}

	public static BaseResult analysisHttpResponse(HttpResponse response, String charset) throws IOException {
		StatusLine statusLine = response.getStatusLine();
		if (statusLine.getStatusCode() == BaseConstants.STATUS_OK) {
			HttpEntity entity = response.getEntity();
			return BaseResult.ok(EntityUtils.toString(entity, charset));
		}
		else {
			StatusEnum statusEnum = StatusEnum.getStatusEnum(Integer.valueOf(statusLine.getStatusCode()));
			if (!ObjectUtil.isEmpty(statusEnum)) {
				return BaseResult.error(statusLine.getStatusCode(),
						String.format("接口请求错误：%s（%s）", statusLine.getReasonPhrase(), statusEnum.getMessage()),
						statusEnum.getDesc());
			}
			else {
				return BaseResult.error(statusLine.getStatusCode(),
						String.format("接口请求错误：%s", statusLine.getReasonPhrase()), "暂无错误描述！");
			}
		}
	}

}
